/*
 * Shawn Fontaine
 * Daniel Pflieger
 * Andrew Goetz
 */

package tests;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import UrlValidator.UrlValidator;
import junit.framework.TestCase;

/*                                             URL SPECIFICATION
 * 
 *                  Url Parts = scheme, scheme data, username, password, host, port, path, query, fragment
 *           Url Construction = either (relative URL) or (absoluate URL), optionally followed by "#" and a fragment
 *               absolute URL = scheme, followed by ":", followed by either a shceme-relative URL, if scheme is a relative scheme, or scheme data otherwise, optionally followed by "?" and a query
 *                     scheme = one letter follwed by zero or more (letter, number, '+', '-', '.')
 *                scheme data = depends on scheme must be zero or more URL units
 *               relative URL = scheme-relative URL, an absolute-path-relative URL, or path-relative URL that does not start with a scheme and ":", optionally followed by a "?" and a query
 *        scheme-relative URL = "//", optionally follwed by userinfo and "@", follwed by a host, optionally followed by ":" and a port, optionally follwed by an absolute-path-relative URL
 *                   Userinfo = username, optionally followed by a ":" and a password
 * 	                 username = zero or more URL units, excluding "/" ":" "?" "@"
 * 	                 password = zero or more URL units, excluding "/" ":" "?" "@"
 *                       port = zero or more digits
 * absolute-path-relative URL = "/" followed by a path-relative URL that does not start with "/"
 *          path-relative URL = zero or more path segments separted from each other by a "/"
 *               path segment = zero or more URL units, excluding "/" and "?"
 *                      query = zero or more URL units
 *                   fragment = zero or more URL units
 *                   URL unit = letters, numbers, !  $  &  '  (  )  *  +  ,  -  .  /  :  ;  =  ?  @  _  ~
 *                   
*/

public class UrlValidatorTest extends TestCase 
{
	UrlValidator urlValidator = new UrlValidator(null, null, UrlValidator.ALLOW_ALL_SCHEMES);

	public UrlValidatorTest(String testName) 
	{
		super(testName);
	}

	public void testManualTest()
	{
		System.out.println("Starting Manual Tests: ");

		Map<String, Boolean> testUrls = new HashMap<String, Boolean>();

		testUrls.put("http://www.google.com", true);
		testUrls.put("HTTP://www.google.com", true);
		testUrls.put("ttp://www.yahoo.com", true);
		testUrls.put("http://google.com", true);
		testUrls.put("http://www.google.com/", true);
		testUrls.put("http://www.amazon.com/", true);
		testUrls.put("http://192.168.1.1", true);
		testUrls.put("http://74.125.224.72/", true);
		testUrls.put("http://www.google.co.nz", true);
		testUrls.put("http://www.google.com/$=page2", true);
		testUrls.put("http://www.apache.org/test/index.html", true);
		testUrls.put("foo://example.com:8000/", true);
		testUrls.put("foo://example.com/over/there?name=ferret", true);
		testUrls.put("http://www.google.xx", true);
		testUrls.put("http://www.google.com.org/", true);
		testUrls.put("http://www.go.goo.google.com.com/", true);
		testUrls.put("http://www.ics.uci.edu/Test/a/x", true);
		testUrls.put("http://www.goo?gle.com", false);
		testUrls.put("3http://www.google.com", false);
		testUrls.put("http:////www.google.com", false);
		testUrls.put("http//www.google.com", false);
		testUrls.put("http://www.google.com%", false);
		testUrls.put("http://localhost:800/GettingStartedService/Calculator", true);

		for (Map.Entry<String, Boolean> entry : testUrls.entrySet())
		{
			boolean result = urlValidator.isValid(entry.getKey());
			if (result != entry.getValue())
			{
				System.out.format("Expected: %-5b | Actual: %-5b | Url: %s\n", entry.getValue(), result, entry.getKey());
			}
		}
		System.out.println("--End Manual Tests--");
	}

	public void testYourFirstPartition()
	{
		System.out.println("Starting Parition One Tests (URLs from different languages:");
		
		Map<String, Boolean> testUrls = new HashMap<String, Boolean>();

		//US urls
		testUrls.put("http://www.google.com", true);
		testUrls.put("http://www.facebook.com", true);
		testUrls.put("http://www.youtube.com", true);
		
		//Japan urls
		testUrls.put("http://www.yahoo.co.jp", true);
		testUrls.put("http://www.google.co.jp", true);
		testUrls.put("http://www.amazon.co.jp", true);
		
		//Germany urls
		testUrls.put("http://www.google.de", true);
		testUrls.put("http://www.ebay.de", true);
		testUrls.put("http://www.amazon.de", true);
		
		//Canada urls
		testUrls.put("http://www.kijiji.ca", true);
		testUrls.put("http://www.gc.ca", true);
		testUrls.put("http://www.amazon.ca", true);
		
		//Mexico urls
		testUrls.put("http://www.google.com.mx", true);
		testUrls.put("http://www.blogspot.mx", true);
		testUrls.put("http://www.mercadolibre.com.mx", true);

		for (Map.Entry<String, Boolean> entry : testUrls.entrySet())
		{
			boolean result = urlValidator.isValid(entry.getKey());

			if (result != entry.getValue())
			{
				System.out.format("Expected: %-5b | Actual: %-5b | Url: %s\n", entry.getValue(), result, entry.getKey());
			}
		}
		
		System.out.println("--End Partition One Tests--");
	}

	public void testYourSecondPartition()
	{
		System.out.println("Starting Parition Two Tests (IP address ranges):");
		int numTests = 1000;
		Random random = new Random();
		int[] IpSections = new int[4];
		
		for(int j = 0; j < numTests; j++)
		{
			StringBuilder url = new StringBuilder();
			boolean isValid = true;
			
			url.append("http://");
			for (int i = 0; i < IpSections.length; i++)
			{
				IpSections[i] = random.nextInt(300);
				if(IpSections[i] > 255)
				{
					isValid = false;
				}
			}
			url.append(IpSections[0]+ "." + IpSections[1] + "." + IpSections[2] + "." + IpSections[3]);

			boolean result = urlValidator.isValid(url.toString());
			if (result != isValid)
			{
				System.out.format("Expected: %-5b | Actual: %-5b | Url: %s\n", isValid, result, url.toString());
			}
		}
		System.out.println("--End Partition Two Tests--");
	}

	public void testIsValid()
	{
		System.out.println("Starting Large Unit Test:");

		//url = scheme + authority + path + query + fragment
		Map<String, Boolean> schemes = new HashMap<String, Boolean>();
		Map<String, Boolean> authorities = new HashMap<String, Boolean>();
		Map<String, Boolean> paths = new HashMap<String, Boolean>();
		Map<String, Boolean> queries = new HashMap<String, Boolean>();
		Map<String, Boolean> fragments = new HashMap<String, Boolean>();
		
		//Testing schemes
		schemes.put("http", true);
		schemes.put("ftp", true);
		schemes.put("3ftp", false);
		schemes.put("3http", false);
		schemes.put("ht//tp", false);
		schemes.put("http++", true);
		schemes.put("http.", true);
		schemes.put("", false);
		
		//Testing authorities
		authorities.put("www.amazon.com", true);
		authorities.put("www.google.com", true);
		authorities.put("www.facebook.com", true);
		authorities.put("192.168.1.1", true);
		authorities.put("amazon.com", true);
		authorities.put("www.amazon.zzzzzzzzzz", false);
		authorities.put("localhost:8000", true);
		authorities.put("www./amazon/.com", false);

		//Testing paths
		paths.put("/testPath/", true);
		paths.put("/testPath2/", true);
		paths.put("///", false);
		paths.put("", true);
		
		//Testing queries
		queries.put("testQuery/", true);
		queries.put("testQuery2/", true);
		queries.put("?url=testQuery3/", true);
		queries.put("", true);
		queries.put("//", false);

		//Testing fragments
		fragments.put("testFragment", true);
		fragments.put("testFragment2", true);
		fragments.put("", true);
		fragments.put("//", false);
		
		for (Map.Entry<String, Boolean> scheme : schemes.entrySet())
		{
			for (Map.Entry<String, Boolean> authority : authorities.entrySet())
			{
				for (Map.Entry<String, Boolean> path : paths.entrySet())
				{
					for (Map.Entry<String, Boolean> query : queries.entrySet())
					{
						for (Map.Entry<String, Boolean> fragment : fragments.entrySet())
						{
							StringBuilder url = new StringBuilder();
							
							url.append(scheme.getKey() + "://" + authority.getKey() + path.getKey() + query.getKey() + fragment.getKey());
							boolean expected = (scheme.getValue() && authority.getValue() && path.getValue() && query.getValue() && fragment.getValue());
							boolean result = urlValidator.isValid(url.toString());
							
							if (result != expected)
							{
								System.out.format("Expected: %-5b | Actual: %-5b | Url: %s\n", expected, result, url.toString());
							}
						}
					}
				}
			}
		}
		System.out.println("--End Large Unit Test--");
	}
}
